/*******************************************************************************
 * File name: 		irq.c
 * Description:	VIC init functions
 * Project:
 * Target: 			LPC2478
 * Compiler: 		arm-none-eabi-gcc
 * Date: 			2010-10-12
 * Author: 			Kuba
 * Based on: 		NXP code examples
 ******************************************************************************/


/*==============================================================================
 Includes
==============================================================================*/
# include <stdbool.h>
# include "LPC24xx.h"
# include "hdr_scb.h"
# include "board.h"

# include "irq.h"

/*==============================================================================
 Defines
==============================================================================*/
# define VIC_SIZE          32

# define VECT_ADDR_OFFSET  0x100 /* Addresses start from address 0xFFFF F100, so offset is 0x100 */
# define VECT_PRIO_OFFSET  0x200 /* Priorities start from address 0xFFFF F200, so offset is 0x200 */

# define IRQ_MASK          (1 << 7)
# define FIQ_MASK          (1 << 6)

#
/*==============================================================================
 Static function prototypes
==============================================================================*/
static inline uint32 getCpsr (void) __attribute__ ((always_inline));
static inline void setCpsr (uint32 val)__attribute__ ((always_inline));

/*==============================================================================
 Global function definitions
==============================================================================*/

/*------------------------------------------------------------------------------
 Function name:	vicInit
 Description:		vectorized interrupt controller initialization
 Parameters:		none
 Returned value: 	none
------------------------------------------------------------------------------*/
void vicInit (void)
{
	uint32 i = 0;
	uint32 *addr;
	uint32 *prio;

	/* VIC initialization */
	VICIntEnClr = 0xFFFFFFFF;
	VICIntSelect = 0; 	         /* zero assigns to the IRQ category */
	VICVectAddr = 0;              /* if IRQ occurs this register will hold the current IRQ address */

	for (i = 0; i < VIC_SIZE; ++i)
	{
		/* Vector addresses start from offset VECT_ADDR_INDEX=0x100 and align it to 4 bytes */
		addr = (uint32 *) (VIC_BASE_ADDR + VECT_ADDR_OFFSET + i * 4);
		/* Vector priorities start from offset VECT_ADDR_INDEX=0x100 and align it to 4 bytes */
		prio = (uint32 *) (VIC_BASE_ADDR + VECT_PRIO_OFFSET + i * 4);

		*addr = 0;                          /* default value */
		*prio = irqLOWEST_PRIORITY;         /* default lowest priority */
	}
}

/*------------------------------------------------------------------------------
 Function name:	irqInit
 Description:		IRQ interrupt initialization
 Parameters:		interrupt number, interrupt service routine address, priority
 Returned value: 	true or false
------------------------------------------------------------------------------*/
bool irqInit (enum irqNum irqNumber, void *isrAddr, enum priority priority)
{
	uint32 *addr;
	uint32 *prio;

	VICIntEnClr = (1 << irqNumber); 		/* disable interrupt in VIC */

	if (irqNumber >= VIC_SIZE)
	{
		return (FALSE);
	}

   addr = (uint32 *) (VIC_BASE_ADDR + VECT_ADDR_OFFSET + irqNumber * 4);
   prio = (uint32 *) (VIC_BASE_ADDR + VECT_PRIO_OFFSET + irqNumber * 4);

   *addr = (uint32) isrAddr; 	         /* get the isr address */
   *prio = priority;

   VICIntEnable |= (1 << irqNumber);	/* enable interrupt */

   return (TRUE);
}

/*------------------------------------------------------------------------------
 Function name:   irqStatus
 Description:     function shows which IRQ interrupts are set
 Parameters:      none
 Returned value:  IRQ status word
------------------------------------------------------------------------------*/
extern uint32 irqStatus    (void)
{
   uint32 is;        /* IRQ status */

   is = VICIRQStatus;
   return (is);
}

/*------------------------------------------------------------------------------
 Function name:   irqEnableCpsr
 Description:     enable IRQ interrupts by altering CPSR. To enable IRQ interrupt,
                    the IRQ bit must be clear
 Parameters:      none
 Returned value:  CPSR value before modification
------------------------------------------------------------------------------*/
extern uint32 irqEnableCpsr (void)
{
   uint32 cpsr;
   cpsr = getCpsr ();
   setCpsr (cpsr & ~IRQ_MASK);
   return cpsr;
}

/*------------------------------------------------------------------------------
 Function name:   irqDisableCpsr
 Description:     disable IRQ interrupts by altering CPSR. To disable IRQ
                   interrupt, the IRQ bit must be set
 Parameters:      none
 Returned value:  CPSR value before modification
------------------------------------------------------------------------------*/
extern uint32 irqDisableCpsr (void)
{
   uint32 cpsr;
   cpsr = getCpsr();
   setCpsr (cpsr | IRQ_MASK);
   return cpsr;
}

/*------------------------------------------------------------------------------
 Function name:   irqRestore
 Description:     restore previous state of IRQ bit in CPSR.
 Parameters:      old value of CPSR
 Returned value:  CPSR value before modification
------------------------------------------------------------------------------*/
extern uint32 irqRestore (uint32 oldCpsr)
{
   uint32 cpsr;
   cpsr = getCpsr();
   setCpsr((cpsr & ~IRQ_MASK) | (oldCpsr & IRQ_MASK));
   return cpsr;
}

/*------------------------------------------------------------------------------
 Function name:   fiqInit
 Description:     FIQ interrupt initialization
 Parameters:      interrupt number, interrupt service routine address
 Returned value:  true or false
------------------------------------------------------------------------------*/
bool fiqInit (enum irqNum irqNumber, void *isrAddr)
{
   uint32 *addr;

   if (irqNumber >= VIC_SIZE)
   {
      return (FALSE);
   }

   VICIntSelect |= (1 << irqNumber);   /* 1 assings to FIQ category */
   addr = (uint32 *) (VIC_BASE_ADDR + VECT_ADDR_OFFSET + irqNumber * 4);
   *addr = (uint32) isrAddr;           /* get the isr address */
   VICIntEnable |= (1 << irqNumber);   /* enable interrupt */

   return (TRUE);
}

/*------------------------------------------------------------------------------
 Function name:   fiqStatus
 Description:     function shows which FIQ interrupts are set
 Parameters:      none
 Returned value:  FIQ status word
------------------------------------------------------------------------------*/
extern uint32 fiqStatus (void)
{
   uint32 fs;        /* FIQ status */

   fs = VICFIQStatus;
   return (fs);
}

/*------------------------------------------------------------------------------
 Function name:   fiqEnableCpsr
 Description:     enable FIQ interrupts by altering CPSR. To enable FIQ interrupt,
                    the FIQ bit must be clear
 Parameters:      none
 Returned value:  CPSR value before modification
------------------------------------------------------------------------------*/
extern uint32 fiqEnableCpsr(void)
{
   uint32 cpsr;
   cpsr = getCpsr ();
   setCpsr (cpsr & ~FIQ_MASK);
   return cpsr;
}

/*------------------------------------------------------------------------------
 Function name:   fiqDisableCpsr
 Description:     disable FIQ interrupts by altering CPSR. To disable FIQ
                   interrupt, the FIQ bit must be set
 Parameters:      none
 Returned value:  CPSR value before modification
------------------------------------------------------------------------------*/
extern uint32 fiqDisableCpsr(void)
{
   uint32 cpsr;
   cpsr = getCpsr();
   setCpsr (cpsr | FIQ_MASK);
   return cpsr;
}

/*------------------------------------------------------------------------------
 Function name:   fiqRestore
 Description:     restore previous state of FIQ bit in CPSR.
 Parameters:      old value of CPSR
 Returned value:  CPSR value before modification
------------------------------------------------------------------------------*/
extern uint32 fiqRestore(uint32 oldCpsr)
{
   uint32 cpsr;
   cpsr = getCpsr();
   setCpsr((cpsr & ~FIQ_MASK) | (oldCpsr & FIQ_MASK));
   return cpsr;
}

/*------------------------------------------------------------------------------
 Function name:   clearIntrpt
 Description:     clears interrupt both IRQ or FIQ in VIC
 Parameters:      interrupt number
 Returned value:  true or false
------------------------------------------------------------------------------*/
extern bool clearIntrpt (enum irqNum irqNumber)
{
   if (irqNumber >= VIC_SIZE)
   {
      return (FALSE);
   }
   VICIntEnClr |= (1 << irqNumber);
   return (TRUE);
}

/*------------------------------------------------------------------------------
 Function name:   swiHandler
 Description:     handler for SWI interrupt:
                1) LR contains saved PC (return address)
                2) LR-4 contains address of SWI instruction and *(LR-4) is exact SWI instrution
                3) SWI instruction has its argument in bits 0-23th
                4) with mask we can get the argument value and decide what to do
                5) ISR is executed in Supervisor mode
 Parameters:      none
 Returned value:  none
------------------------------------------------------------------------------*/
void swiHandler (void)
{
   const uint32 swiMask = 0x00FFFFFF;
   /* LR contains saved PC which is the return address */
   register uint32 *linkPtr asm ("r14");

   switch (*(linkPtr - 1) & swiMask)
   {
   case 0x01:
      /* write here what you need */
      ledBlink(1);
      break;

   case 0x02:
      ledBlink(1);
      break;

   default:
      break;
   }
}

/*==============================================================================
 Static function definitions
==============================================================================*/
/*------------------------------------------------------------------------------
 Function name:   getCpsr
 Description:     save and return CPSR register
 Parameters:      none
 Returned value:  CPSR register
------------------------------------------------------------------------------*/
static inline uint32 getCpsr (void)
{
   uint32 val;
   asm volatile ("MRS %[val], cpsr\n\t":[val]"=r\n\t"(val):);
   return val;
}

/*------------------------------------------------------------------------------
 Function name:   writeCpsr
 Description:     write to CPSR register
 Parameters:      value to write
 Returned value:  none
------------------------------------------------------------------------------*/
static inline void setCpsr (uint32 val)
{
   asm volatile ("MSR cpsr, %[val]\n\t" ::[val]"r"(val));
}

/******************************************************************************
* END OF FILE
******************************************************************************/

